package pl.polidea.treelistview;
import android.util.Log;
/**
* Allows to build tree easily in sequential mode (you have to know levels of
* all the tree elements upfront). You should rather use this class rather than
* manager if you build initial tree from some external data source.
* <p>
* Note, that all ids must be unique. IDs are used to find nodes in the whole
* tree, so they cannot repeat even if they are in different
* sub-trees.
*
* @param <T>
*/
public class TreeBuilder<T> {
private static final String TAG = TreeBuilder.class.getSimpleName();
private static final boolean DEBUG = false;
private final TreeStateManager<T> mManager;
private T mLastAddedId = null;
private int mLastLevel = -1;
public TreeBuilder(final TreeStateManager<T> manager) {
mManager = manager;
}
public void clear() {
mManager.clear();
}
/**
* Adds new relation to existing tree. Child is set as the last child of the
* parent node. Parent has to already exist in the tree, child cannot yet
* exist. This method is mostly useful in case you add entries layer by
* layer - i.e. first top level entries, then children for all parents, then
* grand-children and so on.
*
* @param parent
* parent id
* @param child
* child id
*/
public synchronized void addRelation(final T parent, final T child) {
if (DEBUG) Log.d(TAG, "Adding relation parent:" + parent + " -> child: " + child);
mManager.addAfterChild(parent, child, null);
mLastAddedId = child;
mLastLevel = mManager.getLevel(child);
}
/**
* Adds sequentially new node. Using this method is the simplest way of
* building tree - if you have all the elements in the sequence as they
* should be displayed in fully-expanded tree. You can combine it with add
* relation - for example you can add information about few levels using
* {@link addRelation} and then after the right level is added as parent,
* you can continue adding them using sequential operation.
*
* @param id
* id of the node
* @param level
* its level
*/
public synchronized void sequentiallyAddNextNode(final T id, final int level) {
if (DEBUG) Log.d(TAG, "Adding sequential node " + id + " at level " + level);
if (mLastAddedId == null) {
addNodeToParentOneLevelDown(null, id, level);
} else {
if (level <= mLastLevel) {
final T parent = findParentAtLevel(mLastAddedId, level - 1);
addNodeToParentOneLevelDown(parent, id, level);
} else {
addNodeToParentOneLevelDown(mLastAddedId, id, level);
}
}
}
/**
* Find parent of the node at the level specified.
*
* @param node
* node from which we start
* @param levelToFind
* level which we are looking for
* @return the node found (null if it is topmost node).
*/
private T findParentAtLevel(final T node, final int levelToFind) {
T parent = mManager.getParent(node);
while (parent != null) {
if (mManager.getLevel(parent) == levelToFind) {
break;
}
parent = mManager.getParent(parent);
}
return parent;
}
/**
* Adds note to parent at the level specified. But it verifies that the
* level is one level down than the parent!
*
* @param parent
* parent parent
* @param id
* new node id
* @param level
* should always be parent's level + 1
*/
private void addNodeToParentOneLevelDown(final T parent, final T id,
final int level) {
if (parent == null && level != 0) {
throw new TreeConfigurationException("Trying to add new id " + id
+ " to top level with level != 0 (" + level + ')');
}
if (parent != null && mManager.getLevel(parent) != level - 1) {
throw new TreeConfigurationException("Trying to add new id " + id
+ " <" + level + "> to " + parent + " <"
+ mManager.getLevel(parent)
+ ">. The difference in levels up is bigger than 1.");
}
mManager.addAfterChild(parent, id, null);
setLastAdded(id, level);
}
private void setLastAdded(final T id, final int level) {
mLastAddedId = id;
mLastLevel = level;
}
}